[Day 2] 我們拆解了一個 AI 智慧助理需要哪些核心要素,其中一個很重要的能力就是 RAG
如果今天真的拿到一份 PDF
然後把整份 PDF 丟給 AI,讓它回答問題,真的就能做到 RAG 嗎
因為 RAG 真正重要的問題不是:
「我要怎麼讓 AI 讀文件」
而是:
「我要怎麼讓 AI 在大量文件中,找到真正問題的相關內容」
這也是今天要開始處理的問題
假設我們有一份 100 頁的產品文件
使用者問:
「這個產品支援哪些作業系統」
如果我們每次都把整份 100 頁文件交給 LLM
看起來很簡單,但實際上會遇到幾個問題
這就是 RAG 需要將文件進行切塊 Chunking
簡單來說:
Chunking 就是把一份大型文件拆成多個具有意義的小段落
之後使用者問:
支援哪些作業系統
系統就不需要把整份文件交給 LLM
而是先找到最相關的內容區塊:
再把這段內容交給 LLM
RAG 不只是「把文件切開」
這裡是理解 RAG 非常重要的一個觀念
很多人第一次接觸 RAG,會把它理解成文件、切塊、語音模型
其實完整的 RAG 流程是:
所以 RAG 可以拆成兩個主要階段
而今天我們先處理第一個關鍵步驟:
Chunking
假設我們有這段內容:
本產品支援 Windows 10、Windows 11
以及 Ubuntu 22.04 與 Ubuntu 24.04
使用者可以透過官方網站下載安裝程式
安裝完成後,需要重新啟動系統
如果直接每 20 個字切一次:
Chunk 1
本產品支援 Windows 10、Windows 11
Chunk 2
以及 Ubuntu 22.04 與 Ubuntu 24.04
使用者可以透過官方網站下載安
Chunk 3
裝程式。安裝完成後,需要重新啟動系統
就可能發生一個問題:
語意被切斷了
例如:使用者可以透過官方網站下載安
這段本身就沒有完整意義
因此 Chunking 的目標不是:
「平均切成一樣大的文字」
而是:
「控制 Chunk 大小的同時,盡可能保留完整語意」
實際上有很多種切法
最簡單的方法就是每 500 字切一段
優點:
缺點:
所以實際 RAG 通常不會只使用這種方法
比較常見的方法是:
Recursive Character Text Splitting
概念是按照不同層級的分隔符號進行切割
如果一個段落太長,就繼續往下一層切
這樣可以降低語意被完全切斷的機率
Chunk Size 就是:
每個 Chunk 希望控制在多大的範圍
代表希望每個 Chunk 大約維持在多少個文字單位左右
但這不是一個絕對的
真正重要的是:
Chunk Size 要配合你的資料類型
這是 RAG 裡非常重要的一個概念
如果某個重要資訊剛好位於中間,就可能被切斷
因此我們可以讓兩個 Chunk 保留部份重疊內容就是 Overlap
假設原始文件:
使用者需要先完成帳號註冊
完成註冊後,可以登入系統
登入後即可開始使用 AI 助理
如果剛好切成:
Chunk 1
使用者需要先完成帳號註冊
完成註冊後,可以登入系統
以及:
Chunk 2
登入後即可開始使用 AI 助理
第二個 Chunk 的:
「登入後」
其實依賴前面的資訊。
如果加入 Overlap:
Chunk 1
使用者需要先完成帳號註冊
完成註冊後,可以登入系統
登入後即可開始使用 AI 助理
Chunk 2
登入後即可開始使用 AI 助理。
就能保留更多上下文
因為每個 Chunk 也有可能造成高度重複
結果:
因此:
Chunk Size 與 Chunk Overlap 是需要實驗的參數,而不是固定答案
這也會成為後面 RAG Evaluation 可以實驗的項目
今天我們先不急著建立完整 Vector Database
而是藉由小範例理解基本運作
from langchain_text_splitters import RecursiveCharacterTextSplitter
with open("sample.txt", "r", encoding="utf-8") as f:
text = f.read()
splitter = RecursiveCharacterTextSplitter(
chunk_size=200,
chunk_overlap=50
)
chunks = splitter.split_text(text)
for i, chunk in enumerate(chunks):
print(f"\n Chunk {i + 1}")
print(chunk)
就可以看到文件被拆成多個 Chunk
今天實作時很值得注意的地方
很多人測試 Chunking 時只會看總共有幾個 Chunk
但這個數字本身沒有太大意義
更重要的是語意是否完整
這裡先建立一個重要觀念
Chunking 完成之後,下一步不是直接交給 LLM
而是將每個 Chunk 都會被轉換成向量
之後放進 Vector Database
使用者問題也會被轉成向量
這就是 RAG 的核心之一,通常是藉由餘弦相似度計算相似程度
所以當我們遇到:
「為什麼 AI 回答錯了」
不一定全部都是 LLM 的問題
也可能是:
這也是後面我們會逐步拆解的內容
那今天的範例實驗是為了觀察 RAG 背後是怎麼切分
並理解了:
更重要的是,我們開始建立一個觀念:
RAG 的效果,不只是模型決定的
資料怎麼處理、怎麼切、怎麼搜尋,同樣會直接影響最後的答案
這也是特徵工程的一環
今天我們只是把文件切成
但 AI 還不知道:
「哪一個 Chunk 跟使用者的問題最相關」
因此下一步就是讓系統第一次真正具備:
「從大量文件中找到相關資訊」的能力
[Day 4] 我們就來理解 Embedding:文字到底是怎麼變成機器能比較的向量形式